package top.lyjwn.todo.common.utils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 
 * @author luoyujie
 *
 * @param <T> 所需要生成树的对象
 */
public class BuildTreeUilt<T> {
	private List<T> oblations;
	/**
	 * private Object clazz;
	 * 
	 * private String parentIdAttrName;
	 */

	private Method getId;

	private Method getParentId;

	private Method setChildren;

	/**
	 * 
	 * @param oblations         需要处理的对象列表，这时还未形成树
	 * @param idAttrName        对象的唯一标识符
	 * @param childrenAttrName 对象的子节点
	 * @throws NoSuchMethodException 没有找到指定的方法
	 * @throws SecurityException     指定的方法为私有的方法
	 * @throws Exception             未知的异常
	 */
	public BuildTreeUilt(List<T> oblations, String idAttrName, String childrenAttrName, String parentIdAttrName)
			throws NoSuchMethodException, SecurityException {
		this.oblations = oblations;

		// 获取方法
		// BaseDaoImpl<T>
		Class<? extends Object> clazz = oblations.get(0).getClass();
		this.getId = clazz.getMethod("get" + getMethodName(idAttrName));
		this.getParentId = clazz.getMethod("get" + getMethodName(parentIdAttrName));
		this.setChildren = clazz.getMethod("set" + getMethodName(childrenAttrName), (new ArrayList<T>()).getClass());
	}

	/**
	 * 构建树
	 * 
	 * @return 这是一个多元树，每个节点含N个子节点,第一层也可能包含N个同级节点
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	public List<T> build() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		for (int i = 0; i < this.oblations.size(); i++) {
			List<T> childrens = buildChildrens(this.getId.invoke(oblations.get(i)));
			this.setChildren.invoke(this.oblations.get(i), childrens);
		}
		return oblations;

	}

	/**
	 * 
	 * @param id 对象的唯一标识，注意，不是父节点标识
	 * @return
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
	private List<T> buildChildrens(Object id)
			throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		List<T> childrens = new ArrayList<T>();
		for (int i = 0; i < this.oblations.size(); i++) {
			if (id.equals(this.getParentId.invoke(this.oblations.get(i)))) {
				childrens.add(this.oblations.get(i));
				this.oblations.remove(i);
				i = 0;
				for (int j = 0; j < childrens.size(); j++) {
					List<T> buildChildrens = buildChildrens(this.getId.invoke(childrens.get(j)));
					this.setChildren.invoke(childrens.get(j), buildChildrens);

				}
			}
		}
		return childrens;
	}

	/**
	 * 
	 * @param fildeName 属性名称
	 * @return 返回属性名称
	 */
	private static String getMethodName(String fildeName) {
		byte[] items = fildeName.getBytes();
		items[0] = (byte) ((char) items[0] - 'a' + 'A');
		return new String(items);
	}
}
